use std::{f64, u64};

use umya_spreadsheet::Worksheet;

use super::datas::ColumnData;

pub const NUIL: u8 = 0;
pub const BYTE: u8 = 1;
pub const U_BYTE: u8 = 2;
pub const SHORT: u8 = 3;
pub const U_SHORT: u8 = 4;
pub const INT: u8 = 5;
pub const UINT: u8 = 6;
pub const FLOAT: u8 = 7;
pub const NUMBER: u8 = 8;
pub const STRING: u8 = 9;
pub const ARR_BYTE: u8 = 10;
pub const ARR_U_BYTE: u8 = 11;
pub const ARR_SHORT: u8 = 12;
pub const ARR_U_SHORT: u8 = 13;
pub const ARR_INT: u8 = 14;
pub const ARR_UINT: u8 = 15;
pub const ARR_FLOAT: u8 = 16;
pub const ARR_NUMBER: u8 = 17;
pub const ARR_STRING: u8 = 18;

pub const TYPES: [&'static str; 9] = [
    "byte", "ubyte", "short", "ushort", "int", "uint", "float", "number", "string",
];

pub const TYPES_ARR: [&'static str; 9] = [
    "[byte]", "[ubyte]", "[short]", "[ushort]", "[int]", "[uint]", "[float]", "[number]",
    "[string]",
];

pub const BYTE_MIN: i64 = -128;
pub const BYTE_MAX: i64 = 127;

pub const U_BYTE_MIN: u64 = 0;
pub const U_BYTE_MAX: u64 = 255;

pub const SHORT_MIN: i64 = -32768;
pub const SHORT_MAX: i64 = 32767;

pub const U_SHORT_MIN: u64 = 0;
pub const U_SHORT_MAX: u64 = 65535;

pub const INT_MIN: i64 = -9007199254740991;
pub const INT_MAX: i64 = 9007199254740991;

pub const UINT_MIN: u64 = 0;
pub const UINT_MAX: u64 = 9007199254740991;

pub const FLOAT_MIN: f64 = -3.4028235e+38;
pub const FLOAT_MAX: f64 = 3.4028235e+38;

pub fn get_column_type(file_name: &str, data: &ColumnData) -> u8 {
    let type_str = "string".to_string();
    let type_str_ref = &type_str;
    let type_str_arr = "[string]".to_string();
    let type_str_arr_ref = &type_str_arr;

    //字符串
    if str_eq(&data.low_type, type_str_ref) {
        return STRING;
    }
    if str_eq(&data.low_type, type_str_arr_ref) {
        return ARR_STRING;
    }
    let mut values = Vec::new();
    let is_arr = is_array(&data.low_type);
    //数组类型数据
    if is_arr {
        values.clear();
        for i in &data.datas {
            if !i.is_empty() {
                //数组
                if is_arr {
                    let iter = i.split("|");
                    for v in iter {
                        values.push(v.to_string());
                    }
                } else {
                    values.push(i.to_string());
                }
            }
        }
        return get_true_type(file_name, &data.title, &data.low_type, is_arr, &values);
    }
    get_true_type(file_name, &data.title, &data.low_type, is_arr, &data.datas)
}

fn get_true_type(
    file_name: &str,
    title: &str,
    low_type: &str,
    is_arr: bool,
    values: &Vec<String>,
) -> u8 {
    let mut true_type: u8;
    if values.is_empty() {
        true_type = low2true(low_type);
    } else {
        if is_float(values) {
            true_type = get_min_size_float_type(file_name, title, values);
        } else if is_uint(values) {
            true_type = get_min_size_uint_type(file_name, title, values);
        } else {
            true_type = get_min_size_int_type(file_name, title, values);
        }
        if is_arr {
            true_type = to_arr_type(true_type);
        }
    }
    true_type
}

fn low2true(low: &str) -> u8 {
    match low {
        "nuil" => NUIL,
        "byte" => BYTE,
        "ubyte" => U_BYTE,
        "short" => SHORT,
        "ushort" => U_SHORT,
        "int" => INT,
        "uint" => UINT,
        "float" => FLOAT,
        "number" => NUMBER,
        "string" => STRING,

        "[byte]" => ARR_BYTE,
        "[ubyte]" => ARR_U_BYTE,
        "[short]" => ARR_SHORT,
        "[ushort]" => ARR_U_SHORT,
        "[int]" => ARR_INT,
        "[uint]" => ARR_UINT,
        "[float]" => ARR_FLOAT,
        "[number]" => ARR_NUMBER,
        "[string]" => ARR_STRING,
        _ => panic!("Unknown type: {}", low), // 处理未知类型
    }
}

fn to_arr_type(v: u8) -> u8 {
    match v {
        BYTE => ARR_BYTE,
        U_BYTE => ARR_U_BYTE,
        SHORT => ARR_SHORT,
        U_SHORT => ARR_U_SHORT,
        INT => ARR_INT,
        UINT => ARR_UINT,
        FLOAT => ARR_FLOAT,
        NUMBER => ARR_NUMBER,
        STRING => ARR_STRING,
        _ => panic!("Unknown type: {}", v),
    }
}

/**
 * 获取存储float类型时,最小存储类型
 */
pub fn get_min_size_float_type(_file_name: &str, _title: &str, values: &Vec<String>) -> u8 {
    let mut max = FLOAT_MIN;
    let mut min = FLOAT_MAX;
    for value in values {
        if let Ok(v) = value.parse::<f64>() {
            if v > max {
                max = v;
            }
            if v < min {
                min = v;
            }
        }
    }
    if (FLOAT_MIN..FLOAT_MAX).contains(&min) && (FLOAT_MIN..FLOAT_MAX).contains(&max) {
        return FLOAT;
    }
    NUMBER
}

/**
 * 获取存储int类型时,最小存储类型
 */
pub fn get_min_size_int_type(file_name: &str, title: &str, values: &Vec<String>) -> u8 {
    let mut max = INT_MIN;
    let mut min = INT_MAX;
    for value in values {
        if let Ok(v) = value.parse::<i64>() {
            if v > max {
                max = v;
            }
            if v < min {
                min = v;
            }
        }
    }
    if in_section(min, BYTE_MIN, BYTE_MAX) && in_section(max, BYTE_MIN, BYTE_MAX) {
        return BYTE;
    }
    if in_section(min, SHORT_MIN, SHORT_MIN) && in_section(max, SHORT_MIN, SHORT_MIN) {
        return SHORT;
    }
    if in_section(min, INT_MIN, INT_MAX) && in_section(max, INT_MIN, INT_MAX) {
        return INT;
    }
    panic!(
        "{}: {} 类型值范围过大,超出int范围 {}-{}",
        file_name, title, min, max
    );
}

/**
 * 获取存储uint类型时,最小存储类型
 */
pub fn get_min_size_uint_type(file_name: &str, title: &str, values: &Vec<String>) -> u8 {
    let mut max = UINT_MIN;
    let mut min = UINT_MAX;
    for value in values {
        if let Ok(v) = value.parse::<u64>() {
            if v > max {
                max = v;
            }
            if v < min {
                min = v;
            }
        }
    }
    if in_section(min, U_BYTE_MIN, U_BYTE_MAX) && in_section(max, U_BYTE_MIN, U_BYTE_MAX) {
        return U_BYTE;
    }
    if in_section(min, U_SHORT_MIN, U_SHORT_MIN) && in_section(max, U_SHORT_MIN, U_SHORT_MIN) {
        return U_SHORT;
    }
    if in_section(min, UINT_MIN, UINT_MAX) && in_section(max, UINT_MIN, UINT_MAX) {
        return UINT;
    }
    panic!(
        "{}: {} 类型值范围过大,超出uint范围 {}-{}",
        file_name, title, min, max
    );
}

/**
 * 检测值是否在区间内
 */
pub fn in_section<T: Ord>(value: T, min: T, max: T) -> bool {
    value >= min && value <= max
}

/**
 * 检测类型是否是数组类型
 */
pub fn is_array(value: &str) -> bool {
    for &type_ in &TYPES_ARR {
        if type_ == value {
            return true;
        }
    }
    false
}

/**
 * 检测是否是浮点类型
 */
pub fn is_float(values: &Vec<String>) -> bool {
    for value in values {
        if value.contains(".") {
            return true;
        }
    }
    false
}

/**
 * 检测是否是正整数
 */
pub fn is_uint(values: &Vec<String>) -> bool {
    for value in values {
        if value.contains("-") {
            return false;
        }
    }
    true
}

fn str_eq(a: &String, b: &String) -> bool {
    *a == *b
}

/**
 * 返回首字母大写的字符串
 */
pub fn capitalize_first_letter(s: &str) -> String {
    let mut c = s.chars();
    match c.next() {
        None => String::new(),
        Some(f) => {
            let rest = c.as_str();
            let first = f.to_uppercase().next().unwrap_or(f); // 如果 f 不是字母，则保持原样
            let first_str = first.to_string();

            // 如果首字母已经是大写或者不是字母，则直接返回原字符串
            if first == f || !f.is_ascii_alphabetic() {
                return (first_str.to_owned() + rest).to_owned();
            }
            // 否则，将首字母大写并拼接上剩余的字符串
            first_str.to_owned() + &rest.to_lowercase()
        }
    }
}

/**
 * 检测当前行是否为空
 */
pub fn is_empty_row(sheet: &Worksheet, row: &u32) -> bool {
    let cells = sheet.get_collection_by_row(row);
    for i in cells {
        let cell_value = i.get_value();
        if !cell_value.is_empty() {
            return false;
        }
    }
    true
}
